#include "mainwindow.h"
#include "appsettings.h"
#include "dokermodel.h"
#include "dokerprocessor.h"
#include "dokerversion.h"
#include "widgets/dokerwindow.h"
#include "widgets/sourcedock.h"
#include "widgets/logdock.h"

#include <QtCore/qdatetime.h>
#include <QtCore/qtimer.h>
#include <QtGui/qaction.h>
#include <QtGui/qapplication.h>
#include <QtGui/qdockwidget.h>
#include <QtGui/qevent.h>
#include <QtGui/qfiledialog.h>
#include <QtGui/qgraphicsview.h>
#include <QtGui/qmdiarea.h>
#include <QtGui/qmdisubwindow.h>
#include <QtGui/qmenubar.h>
#include <QtGui/qmessagebox.h>
#include <QtGui/qtabbar.h>
#include <QtGui/qtoolbar.h>

const char *MainWindow::m_languages[] =
{
    QT_TRANSLATE_NOOP("MainWindow", "English"),    "en",
    QT_TRANSLATE_NOOP("MainWindow", "Russian"),    "ru"
};

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    setWindowTitle(tr("Doker"));
    setWindowIcon(QIcon(":/images/doker.png"));
    restoreGeometry(g_appSettings->asByteArray("Geometry"));
    m_model = new DokerModel(this);
    m_win = new DokerWindow(m_model, this);
    m_processor = new DokerProcessor(m_model, this);
    connect(m_processor, SIGNAL(finished()), this, SLOT(setModelControlsEnabled()));
    connect(m_processor, SIGNAL(pageAdded(PageObject*)),
            m_win, SLOT(addPage(PageObject*)));
    connect(m_processor, SIGNAL(textAdded(TextObject*)),
            m_win, SLOT(addText(TextObject*)));
    setCentralWidget(m_win);
    createActions();
    createToolBars();
    createDocks();
    createMenus();
    m_model->create();
}

MainWindow::~MainWindow()
{
    
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    bool needClose = true;
    m_win->apply();
    if (m_model->isModified())
    {
        int res = QMessageBox::question(this, tr("Unsaved Changes"),
                                        QString(tr("There are unsaved changes in document."))
                                        + "<br><br>" + tr("Would you save it now?"),
                                        QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
                                        QMessageBox::Cancel);
        if (res == QMessageBox::Cancel)
            needClose = false;
        else if (res == QMessageBox::Yes)
            m_model->save();
    }
    if (needClose)
    {
        g_appSettings->set("Geometry", saveGeometry());
        g_appSettings->set("DockWidth", m_sourceDock->width());
        g_appSettings->writeAll();
        event->accept();
    }
    else
        event->ignore();

/*
    bool isOk = true;
    while (!m_mdiArea->subWindowList().isEmpty() && isOk)
    {
        QMdiSubWindow *subWin = m_mdiArea->subWindowList().first();
        QWidget *w = subWin->widget();
        isOk = w->close();
        if (isOk)
        {
            m_mdiArea->setActiveSubWindow(subWin);
            m_mdiArea->closeActiveSubWindow();
        }
    }
    if (!isOk)
        event->ignore();
    else
        event->accept();*/
}

void MainWindow::createActions()
{
    QAction *act;

    // FILE
    act = new QAction(QIcon(":/images/file_open.png"), tr("&Open..."), this);
    act->setShortcuts(QKeySequence::Open);
    connect(act, SIGNAL(triggered()), this, SLOT(fileOpen()));
    m_actions["File/Open"] = act;

    act = new QAction(QIcon(":/images/file_save.png"), tr("&Save"), this);
    act->setShortcuts(QKeySequence::Save);
    connect(act, SIGNAL(triggered()), this, SLOT(fileSave()));
    m_actions["File/Save"] = act;

    act = new QAction(QIcon(":/images/process.png"), tr("Run"), this);
    connect(act, SIGNAL(triggered()), this, SLOT(fileRun()));
    act->setShortcuts(QKeySequence::Refresh);
    act->setCheckable(true);
    m_actions["File/Run"] = act;

    act = new QAction(QIcon(":/images/pdf.png"), tr("Export to PDF..."), this);
    connect(act, SIGNAL(triggered()), this, SLOT(fileExport()));
    m_actions["File/Export"] = act;

    act = new QAction(tr("E&xit"), this);
    act->setShortcuts(QKeySequence::Quit);
    connect(act, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));
    m_actions["File/Exit"] = act;

    // VIEW
    QActionGroup *langGroup = new QActionGroup(this);
    const int langCount = (sizeof(m_languages) / sizeof(char*)) / 2;
    const QString currLang = g_appSettings->asString("View/Language");
    for (int i = 0; i < langCount; ++i)
    {
        act = new QAction(tr(m_languages[2*i]), this);
        act->setData(m_languages[2*i + 1]);
        act->setCheckable(true);
        act->setChecked(currLang.compare(m_languages[2*i + 1]) == 0);
        connect(act, SIGNAL(triggered()), this, SLOT(viewLanguage()));
        langGroup->addAction(act);
        m_actions["View/Language/"+QString::number(i)] = act;
    }

    act = new QAction(QIcon(":/images/editor.png"), tr("Show Editor Window"), this);
    act->setCheckable(true);
    connect(act, SIGNAL(triggered(bool)), m_win->editor(), SLOT(setShown(bool)));
    connect(m_win, SIGNAL(editorVisibilityChanged(bool)), act, SLOT(setChecked(bool)));
    m_actions["View/Editor"] = act;

    act = new QAction(QIcon(":/images/viewer.png"), tr("Show Viewer Window"), this);
    act->setCheckable(true);
    connect(act, SIGNAL(triggered(bool)), m_win->viewer(), SLOT(setShown(bool)));
    connect(m_win, SIGNAL(viewerVisibilityChanged(bool)), act, SLOT(setChecked(bool)));
    act->setChecked(true);
    m_actions["View/Viewer"] = act;

    act = new QAction(QIcon(":/images/view_unprinted.png"), tr("View Unprinted Elements"), this);
    act->setCheckable(true);
    connect(act, SIGNAL(triggered(bool)), m_win, SLOT(viewUnprinted(bool)));
    //connect(m_win, SIGNAL(viewerVisibilityChanged(bool)), act, SLOT(setChecked(bool)));
    act->setChecked(true);
    m_actions["View/Unprinted"] = act;

    // HELP
    act = new QAction(tr("&About..."), this);
    connect(act, SIGNAL(triggered()), this, SLOT(helpAbout()));
    m_actions["Help/About"] = act;

}

void MainWindow::createDocks()
{
    m_logDock = new LogDock(this);
    addDockWidget(Qt::BottomDockWidgetArea, m_logDock);

    m_sourceDock = new SourceDock(m_model, this);
    addDockWidget(Qt::LeftDockWidgetArea, m_sourceDock);
    m_sourceDock->setWidth(g_appSettings->asUint("DockWidth", 200));
}

void MainWindow::createMenus()
{
    QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
    fileMenu->addAction(m_actions["File/Open"]);
    fileMenu->addAction(m_actions["File/Save"]);
    fileMenu->addSeparator();
    fileMenu->addAction(m_actions["File/Run"]);
    fileMenu->addSeparator();
    fileMenu->addAction(m_actions["File/Export"]);
    fileMenu->addSeparator();
    fileMenu->addAction(m_actions["File/Exit"]);

    QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
    viewMenu->addAction(m_actions["View/Editor"]);
    viewMenu->addAction(m_actions["View/Viewer"]);
    viewMenu->addSeparator();
    viewMenu->addAction(m_actions["View/Unprinted"]);
    viewMenu->addSeparator();
    QMenu *langMenu = viewMenu->addMenu(tr("Choose language"));
    const int langCount = (sizeof(m_languages) / sizeof(char*)) / 2;
    for (int i = 0; i < langCount; ++i)
        langMenu->addAction(m_actions["View/Language/" + QString::number(i)]);

    QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
    helpMenu->addAction(m_actions["Help/About"]);
}

void MainWindow::createToolBars()
{
    QToolBar *fileToolBar = addToolBar(tr("File"));
    fileToolBar->addAction(m_actions["File/Open"]);
    fileToolBar->addAction(m_actions["File/Save"]);
    fileToolBar->addSeparator();
    fileToolBar->addAction(m_actions["File/Run"]);
    fileToolBar->addSeparator();
    fileToolBar->addAction(m_actions["File/Export"]);

    QToolBar *viewToolBar = addToolBar(tr("View"));
    viewToolBar->addAction(m_actions["View/Editor"]);
    viewToolBar->addAction(m_actions["View/Viewer"]);
    viewToolBar->addSeparator();
    viewToolBar->addAction(m_actions["View/Unprinted"]);
}

void MainWindow::fileExport()
{
    QStringList fileTypes;
    fileTypes << tr("PDF-file (*.pdf)")
              << tr("All Files (*)");
    QString defaultName = QFileInfo(m_model->fullFileName()).baseName() + ".pdf";
    QString fileName = QFileDialog::getSaveFileName(this, tr("Export to PDF"),
                                                    defaultName,
                                                    fileTypes.join(";;"));
    if (!fileName.isEmpty())
        m_win->exportToPdf(fileName);
}

void MainWindow::fileOpen()
{
    m_win->apply();
    if (m_model->isModified())
    {
        int res = QMessageBox::question(this, tr("Unsaved Changes"),
                                        QString(tr("There are unsaved changes in document."))
                                        + "<br><br>" + tr("Would you save it now?"),
                                        QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
                                        QMessageBox::Cancel);
        if (res == QMessageBox::Cancel)
            return;
        if (res == QMessageBox::Yes)
            if (!fileSave())
                return;
    }

    QStringList fileTypes;
    fileTypes << tr("Doker Document (*.dokp *.dokz)")
              << tr("Doker Project (*.dokp)")
              << tr("Doker Bundle (*.dokz)")
              << tr("All Files (*)");
    QString fileName = QFileDialog::getOpenFileName(this, tr("Load Document"),
                                                    g_appSettings->asString("RecentDir"),
                                                    fileTypes.join(";;"));
    if (!fileName.isEmpty())
    {
        g_appSettings->set("RecentDir", QFileInfo(fileName).absolutePath());
        m_win->closeTabs();
        m_win->clearViewer();
        m_sourceDock->clear();
        m_model->load(fileName);
    }
}

void MainWindow::fileRun()
{
    setModelControlsEnabled(false);
    m_logDock->clearAll();
    m_win->apply();
    m_win->clearViewer();

    m_processor->start();
}

bool MainWindow::fileSave()
{
    m_win->apply();
    if (m_model->isUntitled())
    {
        QStringList fileTypes;
        fileTypes << tr("Doker Document (*.dokz)")
                  << tr("All Files (*)");
        QString fileName = QFileDialog::getSaveFileName(this, tr("Save Document"),
                                                        m_model->fullFileName(),
                                                        fileTypes.join(";;"));
        if (fileName.isEmpty())
            return false;
        m_model->setFullFileName(fileName);
    }
    if (!m_model->save())
    {
        // Error
        return false;
    }
    return true;
}

void MainWindow::helpAbout()
{
    QDate today = QDate::currentDate();
    const QString description = tr(
                "<h3>Doker is free open source document processor. "
                "It uses its own script language similar to JavaScript to describe document content.</h3>"
                "Version: <b>%1</b><br/><br/>"
                "Senior developer: <b>Shamil Yakupov</b> (<a href='mailto:shamil@doker.org'>shamil@doker.org</a>)<br/>"
                "Icons by &copy; <b>Mark James</b> (<a href='http://www.famfamfam.com/lab/icons/silk/'>www.famfamfam.com/lab/icons/silk</a>)<br/><br/>"
                "Copyright &copy; 2011&#150;%2 <b>doker.org</b><br/>"
                "<table border=0>"
                "<tr><td>Web:</td><td><a href='http://doker.org/'>doker.org</a></td></tr>"
                "<tr><td>Latest release:</td><td><a href='http://doker.org/latest/'>doker.org/latest</a></td></tr>"
                "<tr><td>Source code:</td><td><a href='http://dokersrc.googlecode.com'>dokersrc.googlecode.com</a></td></tr>"
                "<tr><td>License:</td><td><a href='http://www.gnu.org/licenses/gpl.html'>GNU GPL v3</a></td></tr>"
                "</table>"
                ).arg(DOKER_VER_STR3).arg(today.year());
    QMessageBox::about(this, tr("About Doker"), description);
}

void MainWindow::setModelControlsEnabled(bool enabled)
{
    m_actions["File/Open"]->setEnabled(enabled);
    m_actions["File/Save"]->setEnabled(enabled);
    m_actions["File/Run"]->setEnabled(enabled);
    m_actions["File/Run"]->setChecked(!enabled);

}

void MainWindow::viewLanguage()
{
    QAction *src = qobject_cast<QAction*>(sender());
    if (!src)
        return;

    QMessageBox::information(this, tr("Need restart"),
                             tr("The application need to be restarted to take effect."));

    QString suffix = src->data().toString().toLower().simplified();
    g_appSettings->set("View/Language", suffix);
}
